/*
 * TimeKeeper.java
 *
 * Created on February 25, 2008, 6:28 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.sunspotworld.sensortasks;

import com.sun.spot.io.j2me.radiogram.Radiogram;
import com.sun.spot.peripheral.IDriver;
import com.sun.spot.peripheral.ISleepManager;
import com.sun.spot.peripheral.Spot;
import com.sun.spot.peripheral.radio.IConnectionID;
import com.sun.spot.peripheral.radio.RadioPolicy;
import java.util.Hashtable;
import java.util.Timer;

/**
 * 
 * @author Douglas McClusky
 */
public final class TimeKeeper implements IDriver, IConnectionID {
    private static final int INTER_SLICE_BUFFER = 20;
    private static TimeKeeper keeper = new TimeKeeper();
    private long now=0;
    private long offset = 0;
    private Timer timer = new Timer();
    private long frameSize=0;
    private long totalSample = 0;
    private Hashtable tasks = new Hashtable();
    private long[] taskStartTimes = new long[15];
    private ISleepManager sleepManager = Spot.getInstance().getSleepManager();
    private SensorTask current = null;
    
    /** Creates a new instance of TimeKeeper */
    private TimeKeeper() {
        
        
        //read schedule from flash
        
        
        Spot.getInstance().getRadioPolicyManager().registerConnection(this);
        Spot.getInstance().getRadioPolicyManager().policyHasChanged(this, RadioPolicy.OFF);
        Spot.getInstance().getDriverRegistry().add(this);
    }
    
    public void setFrameSize(long frame) {
        frameSize = frame;
    }
    
    public void skipInterval(long interval) {
        totalSample+=interval + INTER_SLICE_BUFFER;
    }
    
    public SensorTask currentTask() {
        return current;
    }
    
    protected void registerCurrentTask(SensorTask task) {
        current = task;
    }
    
    public boolean schedule(SensorTask task) {
        System.out.println("Deep Sleep Min: " + Spot.getInstance().getSleepManager().getMinimumDeepSleepTime());
        if (tasks.containsKey(task)) {
            timer.schedule(task, frameSize-currentTimeMillis()%frameSize+((Long)tasks.get(task)).longValue());
            return true;
        } else {
            skipInterval(task.getSampleInterval());
            if (totalSample > frameSize) {
                return false;
            }
            Long delay = new Long(totalSample-task.getSampleInterval());
            timer.schedule(task, frameSize-currentTimeMillis()%frameSize+delay.longValue());
            if (tasks.size() >= taskStartTimes.length) {
                expandTaskStartTimes();
            }
            taskStartTimes[tasks.size()] = delay.longValue();
            tasks.put(task, delay);
            return true;
        }
    }
    
    private void expandTaskStartTimes() {
        long[] temp = new long[taskStartTimes.length+5];
        for (int i=0; i<taskStartTimes.length; i++) {
            temp[i] = taskStartTimes[i];
        }
        taskStartTimes = temp;
    }
    
    public void reset() {
        timer.cancel();
        timer = new Timer();
        totalSample = 0;
        tasks = new Hashtable();
        taskStartTimes = new long[15];
    }
    
    public long currentTimeMillis() {
        return System.currentTimeMillis()+offset;
    }
    
    public static TimeKeeper getInstance() {
        return keeper;
    }
    
    public void updateTime(long value, long timestamp) {
        offset = value - timestamp;
    }

    public String getDriverName() {
        return "TimeKeeper";
    }

    public boolean tearDown() {
        return true;
    }

    public void setUp() {
    }

    public void shutDown() {
        
        
        //record schedule to Flash
        
        
    }
    
    /*
    public void updateTime(String valueGPGGA) {
        now = System.currentTimeMillis();
        long val = (long)(Double.parseDouble(valueGPGGA.substring(4))*1000);
        offset = val - now %100000;
        now = 0;
    }//*/
}
